package com.xiayuanxing.arithmetic.DataStructures.Sort;

import java.util.Arrays;

/**
 * @program: arithmetic
 * @description: 堆排序
 * @author: xia yuan xing
 * @create: 2021-10-08 16:19
 */
public class HeapSort {

    public static void main(String[] args) {

        int[] arr = {4,6,8,5,9};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序
     * @param arr
     */
    public static void heapSort(int[] arr){

        int temp = 0;

        for (int i = arr.length / 2 - 1; i >=0 ; i--) {
            adjustHeap(arr,i,arr.length);
        }

        for (int j = arr.length - 1; j >0 ; j--) {
            //交换
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr,0,j);
        }

    }


    /**
     * 将一个数组（二叉树），调整成一个大顶堆
     * 功能：完成以 i对应的非叶子节点的树调整成大顶堆
     * 举例：int[] arr = {4,6,8,5,9}; =>i=1 =>adjustHeap =>得到{4,9,8,5,6}
     * 再次调用adjustHeap,传入的i=0 得到 =>{9,6,8,5,4}
     * @param arr 待调整的数组
     * @param i 表示非叶子节点在数组中的索引
     * @param length 表示对多少个元素继续调整，length 是在逐步减少
     */
    public static void adjustHeap(int[] arr,int i,int length){

        //先取出当前元素的值，保存在临时变量
        int temp = arr[i];

        //k = i * 2 + 1 k是 i节点的左子节点
        for (int k = i * 2 + 1;k < length;k = k * 2 + 1){
            //说明左子节点的值小于右子节点的值
            if (k +1 < length && arr[k] < arr[k+1]){
                //将k指向右子节点
                k++;
            }
            //如果子节点大于父节点
            if (arr[k] > temp){
                //把较大的值赋给当前节点
                arr[i] = arr[k];
                //i 指向k，继续循环比较
                i = k;
            }else {
                break;
            }
        }

        //当for循环结束后，我们已经将以i为父节点的树的最大值放在了局部最顶上
        //将temp值放在调整后的位置
        arr[i] = temp;
    }

}

